// 模拟用户登录成功后需要存储的对象

import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);

// 公共state对象，存储所有组件的状态
const state = {
  user: {
    userName: "", // 用户名
    userPassword: "", // 密码
  },
};

// 解决：刷新浏览器 vuex数据丢失问题  ---- 记得要在App.vue：mounted钩子中存储到sessionStorage中
// const state = window.sessionStorage.getItem("state") != null ? JSON.parse(window.sessionStorage.getItem("state")) : { user: { userName: "", userPassword: "" } };

// 存了就要读取。
// getters: 唯一取值的方法 --- 是计算属性
const getters = {
  // 入参state? 就是上面的公共state,所以从公共state里读取
  getUser(state) {
    // 返回state里的user
    return state.user;
  },
};

// 读到值之后就可以修改值，设置值，更新值
// 唯一可以修改state值的方法 ---- 它是同步阻塞的(当然，这肯定不行。因为我们现在都在说异步.那就使用actions)
const mutations = {
  // 入参：state:就是上面的公共state. user：就是要传进来的新的值，来更新公共state对象中的user
  updateUser(state, user) {
    // 将传进来的要更新的值赋给本来的user
    state.user = user;
  },
};

// 异步调用 mutations。 (因为只有mutations可以更新state中的值，actions是不能修改值的,又必须异步修改，那怎么办呢? 就在actions中调用mutations中的方法，来达到更新值的效果)
const actions = {
  // context: 上下文，就是这一整个js文件。然后通过commit()调用上下文中的方法
  // 那又怎么样调用执行 actions这个方法呢? 也就是说怎么才能让actions中调用的 mutations执行呢?  ---  通过dispatch()
  // 总结：这里是只能：  通过commit调用mutations。 通过dispatch调用 actions
  asyncUpdateUser(context, user) {
    context.commit("updateUser", user);
  },
};

// 以上：全部定义完成，把它暴露出去

export default new Vuex.Store({
  state,
  getters,
  mutations,
  actions,
});

// 这样： store > index.js文件中的配置，我们就配置完成了

// 然后怎么样存储和使用user对象呢? 又在哪里存储和使用呢?
// 存储：一般是在登录成功之后，从后端拿到user对象的值。 通过 this.$store.dispatch("asyncUpdateUser", { userName: this.loginForm.account, userPassword: this.loginForm.passwrod }); 存储  --------- 参数1：actions的名称， 参数2：要存储的对象
// 使用：在项目中任何一个页面可以获取user对象。通过 {{$store.getters.getUser.userName}}   或  this.$store.getters.getUser.userPassword

// 此时： 在项目任何一个页面中都可以拿到 state中存储的用户名了。 但是注意:  一刷新页面 值就不见了！！！！ 一刷新浏览器 vuex的数据消失了 ！！！
// 因为： vuex的状态存储是响应式的，当Vue组件从store中读取状态的时候，若store中的状态发生变化，那么相应的组件也会得到更新。但有一个问题就是：vuex存储的数据只是在页面中，相当于我们定义的全局变量，刷新之后，里边的数据就会恢复到初始化状态(初始化状态：就是const state 中定义的初始值)。但这种情况并不是我们想要的。
// 那么怎么解决这个问题呢?
// 监听页面是否刷新，如果页面刷新了，将state对象存入到 sessionStorage中。页面打开之后，判断sessionStorage中是否存在state对象，如果存在，则说明页面是被刷新过的，将sessionStorage中存的数据取出来给vuex中的state赋值。如果不存在，说明是第一次打开，则取vuex中定义的state初始值。

// 修改代码：在App.vue中增加监听刷新事件： mounted钩子中 : 通过window.addEventListener('unload', ()=>{存到seessonStorage的函数})
// 然后在读数据的时候，也就是 定义state的时候做判断。

// 模块化
// 先介绍模块化： 由于使用单一状态树，应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂是，store对象就有可能变得相当臃肿。为了解决这个问题，vuex允许我们将store分割成模块(module),每个模块拥有自己的state、mutation、action、getter、甚至是嵌套子模块--- 从上至下进行同样方式的分割

// 在 store > 目录下 创建一个名为modules的目录，并创建一个名为user.js的文件

// 注意：遇到的浏览器刷新vuex数据丢失的问题：
// 登录成功页面存储的状态 在别的页面获取时，刷新页面数据丢失  --- 通过存储到sesionStorage的方式解决这个问题
// 在layout页面调接口拿到的值存储的状态 在别的页面获取时，刷新页面时数据并不会丢失

// 模块化写法参考 ./store

/* 
  App.vue中是如何写的呢?
    mounted() {
      window.addEventListener("unload", this.saveState);
    },
    saveState() {
      // window.sessionStorage.setItem("state", JSON.stringify(this.$store.state));
      // 模块化之后 -- 这里应该指向user
      window.sessionStorage.setItem("state", JSON.stringify(this.$store.state.user));
    },

*/
